// Copyright 2011-2012, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef LIBV_FILE_REQUEST_COMPLETION_HANDLE_HPP_
#define LIBV_FILE_REQUEST_COMPLETION_HANDLE_HPP_

#include <libv/acfile.h>
#include <libv/file/basic_file.h>
#include <libv/file/basic_request_handle.h>


namespace libv
{

ACFile::RequestCompletionHandle::RequestCompletionHandle()
    : request_handle_(NULL),
      ref_count_(new int(1))
{
    // Гарантируем, что поля обнулятся.
    // Вообще вызов new T() в отличие от new T тоже это гарантирует,
    // но Microsoft по этому поводу пишут, что на такую мелочь им все равно.
    const RequestHandle zero_request_handle = { 0 };
    request_handle_ = new RequestHandle(zero_request_handle);
}



ACFile::RequestCompletionHandle::RequestCompletionHandle(
    FileHandle file_handle,
    const RequestHandle& request_handle,
    const uint32_t& num_bytes_to_transfer,
    enum Operation operation)
    : BasicRequestHandle(
           file_handle,
           FileSlice(RequestHandle2FileSilce(request_handle,
                                             num_bytes_to_transfer)),
           operation,
           PENDING),
      request_handle_(new RequestHandle(request_handle)),
      ref_count_(new int(1)) {}



ACFile::RequestCompletionHandle::RequestCompletionHandle(
    const ACFile::RequestCompletionHandle& rhv)
    : BasicRequestHandle(rhv.file_handle_,
                         rhv.file_slice_,
                         rhv.operation_,
                         rhv.last_error_),
      request_handle_(rhv.request_handle_),
      ref_count_(rhv.ref_count_)
{
    ++(*ref_count_);
}



ACFile::RequestCompletionHandle::~RequestCompletionHandle()
{
    if ( --(*ref_count_) == 0 )
        Destruct();
}



ACFile::RequestCompletionHandle& ACFile::RequestCompletionHandle::operator=(
    const ACFile::RequestCompletionHandle& rhv)
{
    if ( this != &rhv )
    {
        if ( --(*ref_count_) == 0 )
            Destruct();

        file_handle_ = rhv.file_handle_;
        file_slice_ = rhv.file_slice_;
        operation_ = rhv.operation_;
        last_error_ = rhv.last_error_;
        request_handle_ = rhv.request_handle_;
        ref_count_ = rhv.ref_count_;

        ++(*ref_count_);
    }
    return *this;
}



enum ACFile::RequestCompletionHandle::Status
    ACFile::RequestCompletionHandle::Status() const
{
    // Для объекта, созданного конструктором по умолчанию.
    if ( file_handle_ == LIBV_FILE_INVALID_HANDLE )
        return COMPLETED;
    return StatusImpl();
}



bool ACFile::RequestCompletionHandle::WaitUntilFinished() const
{
    if ( file_handle_ == LIBV_FILE_INVALID_HANDLE )
        return true;
    return WaitUntilFinishedImpl();
}



void ACFile::RequestCompletionHandle::Clear()
{
    file_handle_ = LIBV_FILE_INVALID_HANDLE;
    operation_ = NONE;
    file_slice_ = FileSlice(0,0);
}



////////////////////////////////// PRIVATE /////////////////////////////////////



void ACFile::RequestCompletionHandle::Destruct()
{
    assert(ref_count_ != NULL && *ref_count_ == 0);

    DestructImpl();

    delete ref_count_;
    ref_count_ = NULL;

    delete request_handle_;
    request_handle_ = NULL;

    Clear();
}

}  // libv

#endif  // LIBV_FILE_REQUEST_COMPLETION_HANDLE_HPP_
